home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / vroom / vroom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  41.0 KB  |  1,834 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <malloc.h>
  23. #include <math.h>
  24. #include <sys/stat.h>
  25.  
  26. #include <X11/Intrinsic.h>
  27. #include <X11/StringDefs.h>
  28. #include <X11/cursorfont.h>
  29. #include <X11/SGIScheme.h>
  30. #include <Xm/Xm.h>
  31. #include <Xm/MwmUtil.h>
  32. #include <Xm/CascadeB.h>
  33. #include <Xm/Form.h>
  34. #include <Xm/Frame.h>
  35. #include <Xm/Label.h>
  36. #include <Xm/MainW.h>
  37. #include <Xm/MessageB.h>
  38. #include <Xm/PushB.h>
  39. #include <Xm/RowColumn.h>
  40. #include <Xm/Separator.h>
  41. #include <Xm/Text.h>
  42. #include <Xm/ToggleB.h>
  43. #include "Row.h"
  44.  
  45. #include "vroom.h"
  46. #include "body.h"
  47. #include "track.h"
  48. #include "ogl.h"
  49. #include "car.h"
  50. #include "solo.h"
  51. #include "framerate.h"
  52. #include "playmode.h"
  53. #include "client.h"
  54. #include "sound.h"
  55. #include "messages.h"
  56.  
  57. #if !defined(VROOM_DEFAULT_DIR)
  58. #define    VROOM_DEFAULT_DIR    "."
  59. #endif /* VROOM_DEFAULT_DIR */
  60.  
  61. #if !defined(VROOM_DEFAULT_REC_DIR)
  62. #define    VROOM_DEFAULT_REC_DIR    "."
  63. #endif /* VROOM_DEFAULT_REC_DIR */
  64.  
  65. #define MAX_VISIBLE_HELP_LINES    24
  66.  
  67.  
  68. /* BEGIN PROTOTYPES -S vroom.c */
  69. static void     calculateFrameRate( void ) ;
  70. static Widget   createHelpWidget( Widget parent, char *helpMessage,
  71.                     XtCallbackProc nextHelp, char **helpFileName ) ;
  72. static void     createIntroWindow( Widget parent ) ;
  73. static void     createMainWindow( Widget parent, Dimension w, Dimension h ) ;
  74. static Widget   createMenu( Widget menuBar, char *label ) ;
  75. static Widget   createScrolledTextDialog( Widget parent, char *helpMessage,
  76.                     XtCallbackProc nextHelp, char **helpFileName ) ;
  77. static void     destroyWidgetCB( Widget w, XtPointer clientData,
  78.                     XtPointer callData ) ;
  79. static void     determineMyName( void ) ;
  80. static void     getDefaultDataDir( void ) ;
  81. static char *   getHelpMessage( char *file ) ;
  82. static void     initSound( void ) ;
  83. static Boolean  masterWorkProc( XtPointer clientData ) ;
  84. static int      numberOfLines( const char *text ) ;
  85. static void     showMessage( char *msg, unsigned char dialogType,
  86.                     XtCallbackProc callback, XtPointer userData ) ;
  87. /* END PROTOTYPES -S vroom.c */
  88.  
  89.  
  90. static String    fallbacks[] = {
  91.         "*overlayFont: -*-helvetica-bold-r-normal--20-*",
  92.         "*msgLabel.overlayFont: -*-helvetica-medium-r-normal--18-*",
  93.         "Vroom.geometry: +100+100",
  94.         "*keyboardFocusPolicy: pointer",
  95.         "*useSchemes: true",
  96.         "*sgiMode: true",
  97.             /* Below in case schemes & sgiMode is off */
  98.         "*fontList: -*-helvetica-bold-r-normal--14-*",
  99.         "*foreground: black",
  100.         "*background: #aaaaaa",
  101.         "*highlightColor: white",
  102.         NULL
  103.         } ;
  104.  
  105. char        *basename = "vroom" ;
  106. char        *myName = "me" ;
  107. char        *defaultDataDir ;
  108. char        *defaultRecDir ;
  109. int        freeTime = 1 ;
  110. int        nPlayers = 1 ;
  111. int        nCars = 1 ;
  112. int        self = 0 ;
  113. int        playMode = VROOM_NO_MODE ;
  114. int        showSpeedBars = 1 ;
  115. long        myHostId = 0 ;
  116. float        currentTime = 0.0f ;
  117. float        frameRate = 0.0f ;
  118. float        speedFactor = 1.0f / TOP_SPEED ;
  119. Widget        topLevel ;
  120. Widget        mainWindow = NULL ;
  121. Widget        introWindow = NULL ;
  122. Widget        messageForm ;
  123. Widget        playModeForm ;
  124. Widget        localCourseForm ;
  125. Widget        serverCourseForm ;
  126. Widget        serverForm ;
  127. Widget        resultsForm ;
  128. Widget        previewForm ;
  129. Widget        skillForm ;
  130. Widget        courseVoteForm ;
  131. Widget        nameForm ;
  132. Widget        msgLabel ;
  133. XtAppContext    appContext ;
  134. PlayerStruct    player[MAX_PLAYERS] ;
  135.  
  136. extern int    debugOn ;
  137.  
  138. static int        startedX = 0 ;
  139. static int        workProcMask = 0 ;
  140. static XtWorkProcId    lastWorkProc = 0 ;
  141.  
  142.  
  143. typedef    struct    {
  144.         Boolean        audio ;
  145.         char        *name ;
  146.         char        *defaultDataDir ;
  147.         char        *defaultRecDir ;
  148.         int        ttl ;
  149.         Dimension    mainWidth ;
  150.         Dimension    mainHeight ;
  151.         } AppData, *AppDataPtr ;
  152.  
  153. AppData        AppRes ;
  154.  
  155. static XtResource    resources[] = {
  156.         { "audio", "Audio", XtRBoolean, sizeof(Boolean),
  157.         XtOffset( AppDataPtr, audio ), XtRString, "True" },
  158.         { "name", "Name", XtRString, sizeof( char * ),
  159.         XtOffset( AppDataPtr, name ), XtRString, "" },
  160.         { "defaultDataDir", "DefaultDataDir", XtRString,
  161.         sizeof( char * ), XtOffset( AppDataPtr, defaultDataDir ),
  162.         XtRString, "" },
  163.         { "defaultRecDir", "DefaultRecDir", XtRString,
  164.         sizeof( char * ), XtOffset( AppDataPtr, defaultRecDir ),
  165.         XtRString, "" },
  166.         { "ttl", "Ttl", XtRInt, sizeof(int),
  167.         XtOffset( AppDataPtr, ttl ), XtRString, "8" },
  168.         { "mainWidth", "MainWidth", XtRDimension, sizeof(Dimension),
  169.         XtOffset( AppDataPtr, mainWidth ), XtRString, "600" },
  170.         { "mainHeight", "MainHeight", XtRDimension, sizeof(Dimension),
  171.         XtOffset( AppDataPtr, mainHeight ), XtRString, "600" },
  172.         } ;
  173.  
  174. Sfx            alertSfx ;
  175. Sfx            changeLaneSfx ;
  176. Sfx            cheerSfx ;
  177. Sfx            collideSfx ;
  178. Sfx            crashSfx ;
  179. Sfx            introSfx ;
  180. Sfx            lastlapSfx ;
  181. Sfx            motorSfx ;
  182. Sfx            startSfx ;
  183. Sfx            toneSfx ;
  184. Sfx            squealSfx ;
  185.  
  186.  
  187.  
  188. /*------------------------------------------------------------------------------
  189.  * Main routine.
  190.  *----------------------------------------------------------------------------*/
  191. void
  192. main(
  193.     int    argc,
  194.     char    **argv
  195.     )
  196. {
  197.     int    n ;
  198.     Arg    args[2] ;
  199.  
  200.     /*
  201.      * Get basename.
  202.      */
  203.     if( ( basename = strrchr( argv[0], '/' ) ) == NULL )
  204.         basename = argv[0] ;
  205.     else
  206.         basename++ ;
  207.  
  208.     srand( (unsigned int)getpid() ) ;
  209.  
  210.     topLevel = XtAppInitialize( &appContext, "Vroom", NULL, 0,
  211.                 &argc, argv, fallbacks, NULL, 0 ) ;
  212.     n = 0 ;
  213.     XtSetArg( args[n], XmNallowShellResize, True ) ; n++ ;
  214.     XtSetValues( topLevel, args, n ) ;
  215.  
  216.         XtGetApplicationResources( topLevel, (XtPointer)&AppRes, resources,
  217.                 XtNumber( resources ), NULL, 0 ) ;
  218.  
  219.     createIntroWindow( topLevel ) ;
  220.  
  221.     determineMyName() ;
  222.  
  223.     initRobotNames() ;
  224.  
  225.     initTime() ;
  226.  
  227. #ifdef DEBUG
  228.     if( argc == 2 )
  229.     {
  230.         sscanf( argv[1], "%x", &myHostId ) ;
  231.         if( myHostId == 0 )
  232.         {
  233.             fprintf( stderr, "usage: %s [hex_ip_address]\n",
  234.                 basename ) ;
  235.             exit( 1 ) ;
  236.         }
  237.     }
  238.     else
  239.     {
  240.         myHostId = gethostid() ;
  241.     }
  242. #else
  243.     myHostId = gethostid() ;
  244. #endif /* DEBUG */
  245.  
  246.     /*
  247.      * Set umask to 0 for writing out records.
  248.      */
  249.     umask( 0 ) ;
  250.  
  251.     setAdminForm( playModeForm ) ;
  252.     XtRealizeWidget( topLevel ) ;
  253.     startedX = 1 ;
  254.     getDefaultDataDir() ;
  255.     unbusyCursor() ;
  256.     if( AppRes.audio )
  257.     {
  258.         initSound() ;
  259.     }
  260.     XtAppMainLoop( appContext ) ;
  261. }
  262.  
  263.  
  264.  
  265. /*------------------------------------------------------------------------------
  266.  * Make the main window.
  267.  *----------------------------------------------------------------------------*/
  268. static void
  269. createMainWindow(
  270.     Widget        parent,
  271.     Dimension    w,
  272.     Dimension    h
  273.     )
  274. {
  275.     int        n ;
  276.     Widget        base ;
  277.     Widget        frame ;
  278.     Widget        menuBar ;
  279.     Widget        menuPane ;
  280.     Widget        cascade ;
  281.     Arg        args[10] ;
  282.  
  283.     /*
  284.      * Create the mother form.
  285.      */
  286.     n = 0 ;
  287.     XtSetArg( args[n], XmNwidth, w ) ; n++ ;
  288.     XtSetArg( args[n], XmNheight, h ) ; n++ ;
  289.     mainWindow = XtCreateWidget( "main", xmMainWindowWidgetClass,
  290.                     parent, args, n ) ;
  291.  
  292.     n = 0 ;
  293.     base = XtCreateManagedWidget( "base", xmFormWidgetClass,
  294.                      mainWindow, args, n ) ;
  295.  
  296.     n = 0 ;
  297.     XtSetArg( args[n], XmNshadowType, XmSHADOW_IN ) ; n++ ;
  298.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_FORM ) ; n++ ;
  299.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  300.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  301.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_FORM ) ; n++ ;
  302.     frame = XtCreateManagedWidget( "oglFrame", xmFrameWidgetClass,
  303.                     base, args, n ) ;
  304.  
  305.     /*
  306.      * Create main OpenGL widget.
  307.      */
  308.     n = 0 ;
  309.     createMainOglWidget( frame, args, n ) ;
  310.  
  311.     /*
  312.      * Create the message label.
  313.      */
  314.     n = 0 ;
  315.     XtSetArg( args[n], XmNshadowType, XmSHADOW_IN ) ; n++ ;
  316.     XtSetArg( args[n], XmNshadowThickness, 2 ) ; n++ ;
  317.     frame = XtCreateManagedWidget( "frame", xmFrameWidgetClass,
  318.                     mainWindow, args, n ) ;
  319.  
  320.     n = 0 ;
  321.     msgLabel = XtCreateManagedWidget( "msgLabel", xmLabelWidgetClass,
  322.                         frame, args, n ) ;
  323.  
  324.     /*
  325.      * Create menu bar.
  326.      */
  327.     n = 0 ;
  328.     menuBar = XmCreateMenuBar( mainWindow, "menuBar", args, n ) ;
  329.     XtManageChild( menuBar ) ;
  330.  
  331.     /*
  332.      * Create first pull-down menu.
  333.      */
  334.     menuPane = createMenu( menuBar, "System" ) ;
  335.  
  336.         /*
  337.          * Create entries in menu.
  338.          */
  339.         addMenuPushButton( menuPane, "About...", args, 0,
  340.                     aboutCB, NULL ) ;
  341.  
  342.         addMenuPushButton( menuPane, "Quit", args, 0,
  343.                     exitCB, 0 ) ;
  344.  
  345.     /*
  346.      * Create Help button (not menu).
  347.      */
  348.     n = 0 ;
  349.     cascade = XtCreateManagedWidget( "Help", xmCascadeButtonWidgetClass,
  350.                     menuBar, args, n ) ;
  351.     XtAddCallback( cascade, XmNactivateCallback, showRaceHelpCB, NULL ) ;
  352.  
  353.     /*
  354.      * Inform menu bar about which widget should be displayed in the
  355.      * help button position (far right side).
  356.      */
  357.     n = 0 ;
  358.     XtSetArg( args[n], XmNmenuHelpWidget, cascade ) ; n++ ;
  359.     XtSetValues( menuBar, args, n ) ;
  360.  
  361.     /*
  362.      * Define main window areas.
  363.      */
  364.     n = 0 ;
  365.     XtSetArg( args[n], XmNmessageWindow, frame ) ; n++ ;
  366.     XtSetArg( args[n], XmNmenuBar, menuBar ) ; n++ ;
  367.     XtSetArg( args[n], XmNworkWindow, base ) ; n++ ;
  368.     XtSetValues( mainWindow, args, n ) ;
  369. }
  370.  
  371.  
  372.  
  373. /*------------------------------------------------------------------------------
  374.  * Make the main intro window.
  375.  *----------------------------------------------------------------------------*/
  376. static void
  377. createIntroWindow(
  378.     Widget        parent
  379.     )
  380. {
  381.     int        n ;
  382.     Arg        args[10] ;
  383.     XmString    str ;
  384.     Widget        oglFrame ;
  385.  
  386.     /*
  387.      * Create the mother form.
  388.      */
  389.     n = 0 ;
  390.     XtSetArg( args[n], XmNfractionBase, 100 ) ; n++ ;
  391.     introWindow = XtCreateWidget( "introForm", xmFormWidgetClass,
  392.                     parent, args, n ) ;
  393.  
  394.     controlIntroWindow( 1 ) ;
  395.  
  396.     n = 0 ;
  397.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_NONE ) ; n++ ;
  398.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  399.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  400.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_FORM ) ; n++ ;
  401.     messageForm = XtCreateManagedWidget( "messageForm", xmFormWidgetClass,
  402.                     introWindow, args, n ) ;
  403.  
  404.     n = 0 ;
  405.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_FORM ) ; n++ ;
  406.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  407.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_POSITION ) ; n++ ;
  408.     XtSetArg( args[n], XmNrightPosition, 50 ) ; n++ ;
  409.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_WIDGET ) ; n++ ;
  410.     XtSetArg( args[n], XmNbottomWidget, messageForm ) ; n++ ;
  411.     playModeForm = XtCreateWidget( "playModeForm", xmFormWidgetClass,
  412.                     introWindow, args, n ) ;
  413.  
  414.     localCourseForm = XtCreateWidget( "localCourseForm", xmFormWidgetClass,
  415.                     introWindow, args, n ) ;
  416.  
  417.     serverCourseForm = XtCreateWidget( "serverCourseForm",
  418.                 xmFormWidgetClass, introWindow, args, n ) ;
  419.  
  420.     serverForm = XtCreateWidget( "serverForm", xmFormWidgetClass,
  421.                     introWindow, args, n ) ;
  422.  
  423.     resultsForm = XtCreateWidget( "resultsForm", xmFormWidgetClass,
  424.                     introWindow, args, n ) ;
  425.  
  426.     previewForm = XtCreateWidget( "previewForm", xmFormWidgetClass,
  427.                     introWindow, args, n ) ;
  428.  
  429.     skillForm = XtCreateWidget( "skillForm", xmFormWidgetClass,
  430.                     introWindow, args, n ) ;
  431.  
  432.     courseVoteForm = XtCreateWidget( "courseVoteForm", xmFormWidgetClass,
  433.                     introWindow, args, n ) ;
  434.  
  435.     nameForm = XtCreateWidget( "nameForm", xmFormWidgetClass,
  436.                     introWindow, args, n ) ;
  437.  
  438.     str = XmStringCreateLocalized( "Waiting for other players to choose "
  439.                     "a course." ) ;
  440.     n = 0 ;
  441.     XtSetArg( args[n], XmNlabelString, str ) ; n++ ;
  442.     XtSetArg( args[n], XmNalignment, XmALIGNMENT_CENTER ) ; n++ ;
  443.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_FORM ) ; n++ ;
  444.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  445.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  446.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_FORM ) ; n++ ;
  447.     XtCreateManagedWidget( "label", xmLabelWidgetClass,
  448.                     courseVoteForm, args, n ) ;
  449.     XmStringFree( str ) ;
  450.  
  451.     createPlayModeChooser( playModeForm ) ;
  452.  
  453.     /*
  454.      * Create the frame for the intro OpenGL window.
  455.      */
  456.     n = 0 ;
  457.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_FORM ) ; n++ ;
  458.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_POSITION ) ; n++ ;
  459.     XtSetArg( args[n], XmNleftPosition, 50 ) ; n++ ;
  460.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  461.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_WIDGET ) ; n++ ;
  462.     XtSetArg( args[n], XmNbottomWidget, messageForm ) ; n++ ;
  463.     XtSetArg( args[n], XmNshadowType, XmSHADOW_IN ) ; n++ ;
  464.     XtSetArg( args[n], XmNshadowThickness, 3 ) ; n++ ;
  465.     XtSetArg( args[n], XmNwidth, 400 ) ; n++ ;
  466.     XtSetArg( args[n], XmNheight, 400 ) ; n++ ;
  467.     oglFrame = XtCreateManagedWidget( "introOglFrame", xmFrameWidgetClass,
  468.                     introWindow, args, n ) ;
  469.  
  470.     /*
  471.      * Create the OpenGL widget for displaying the intro graphic.
  472.      */
  473.     createIntroOglWidget( oglFrame, args, 0 ) ;
  474. }
  475.  
  476.  
  477.  
  478. /*------------------------------------------------------------------------------
  479.  * Exit program callback function definition.
  480.  *----------------------------------------------------------------------------*/
  481. void
  482. exitCB(
  483.     Widget        w,
  484.     XtPointer    clientData,
  485.     XtPointer    callData )
  486. {
  487.     if( playMode == VROOM_TEAM )
  488.     {
  489.         teamExit() ;
  490.     }
  491.     exit( (int)clientData ) ;
  492. }
  493.  
  494.  
  495.  
  496. /*------------------------------------------------------------------------------
  497.  * Print string callback function definition.
  498.  *----------------------------------------------------------------------------*/
  499. void
  500. printCB(
  501.     Widget        w,
  502.     XtPointer    clientData,
  503.     XtPointer    callData )
  504. {
  505.     printf( "printCB: `%s'\n", (char *)clientData ) ;
  506. }
  507.  
  508.  
  509.  
  510. /*------------------------------------------------------------------------------
  511.  * Add a button and assign the activation callback procedure.
  512.  *----------------------------------------------------------------------------*/
  513. Widget
  514. addMenuPushButton(
  515.     Widget        parent,
  516.     char        *label,
  517.     Arg        args[],
  518.     int        n,
  519.     XtCallbackProc    cb,
  520.     XtPointer    callData
  521.     )
  522. {
  523.     Widget    button ;
  524.  
  525.     button = XtCreateManagedWidget( label, xmPushButtonWidgetClass,
  526.                     parent, args, n ) ;
  527.     if( cb != NULL )
  528.     {
  529.         XtAddCallback( button, XmNactivateCallback, cb, callData ) ;
  530.     }
  531.  
  532.     return( button ) ;
  533. }
  534.  
  535.  
  536.  
  537. /*------------------------------------------------------------------------------
  538.  * Create a pull-down menu.
  539.  *----------------------------------------------------------------------------*/
  540. static Widget
  541. createMenu(
  542.     Widget  menuBar,
  543.     char    *label
  544.     )
  545. {
  546.     int     n ;
  547.     Arg     args[10] ;
  548.     Widget    menuPane ;
  549.  
  550.     /*
  551.      * Create holder for first pull-down menu.
  552.      */
  553.     n = 0 ;
  554.     XtSetArg( args[n], XmNisHomogeneous, False ) ; n++ ;
  555.     menuPane = XmCreatePulldownMenu( menuBar, "menuPane", args, n ) ;
  556.  
  557.     /*
  558.      * Connect menu to menu bar.
  559.      */
  560.     n = 0 ;
  561.     XtSetArg( args[n], XmNsubMenuId, menuPane ) ; n++ ;
  562.     (void)XtCreateManagedWidget( label, xmCascadeButtonWidgetClass,
  563.                     menuBar, args, n ) ;
  564.  
  565.     return( menuPane ) ;
  566. }
  567.  
  568.  
  569.  
  570. /*------------------------------------------------------------------------------
  571.  * Display an information string.
  572.  *----------------------------------------------------------------------------*/
  573. void
  574. postInfo(
  575.     XtCallbackProc    callback,
  576.     XtPointer    userData,
  577.     char        *fmt,
  578.     ...
  579.     )
  580. {
  581.     va_list        args ;
  582.     char        msg[1024] ;
  583.  
  584.     va_start( args, fmt ) ;
  585.     if( startedX )
  586.     {
  587.         vsprintf( msg, fmt, args ) ;
  588.  
  589.         showMessage( msg, XmDIALOG_INFORMATION, callback, userData ) ;
  590.     }
  591.     else
  592.     {
  593.         vprintf( fmt, args ) ;
  594.     }
  595.     va_end( args ) ;
  596. }
  597.  
  598.  
  599.  
  600. /*------------------------------------------------------------------------------
  601.  * Handle a minor error.
  602.  *----------------------------------------------------------------------------*/
  603. void
  604. minorError(
  605.     XtCallbackProc    callback,
  606.     XtPointer    userData,
  607.     char        *fmt,
  608.     ...
  609.     )
  610. {
  611.     va_list        args ;
  612.     char        msg[512] ;
  613.  
  614.     va_start( args, fmt ) ;
  615.     if( startedX )
  616.     {
  617.         vsprintf( msg, fmt, args ) ;
  618.  
  619.         showMessage( msg, XmDIALOG_WARNING, callback, userData ) ;
  620.     }
  621.     else
  622.     {
  623.         vprintf( fmt, args ) ;
  624.     }
  625.     va_end( args ) ;
  626. }
  627.  
  628.  
  629.  
  630. /*------------------------------------------------------------------------------
  631.  * Handle a fatal error.
  632.  *----------------------------------------------------------------------------*/
  633. void
  634. fatalError(
  635.     char    *fmt,
  636.     ...
  637.     )
  638. {
  639.     va_list        args ;
  640.     char        msg[512] ;
  641.     XEvent        event ;
  642.  
  643.     va_start( args, fmt ) ;
  644.     if( startedX )
  645.     {
  646.         vsprintf( msg, fmt, args ) ;
  647.  
  648.         showMessage( msg, XmDIALOG_ERROR, exitCB, (XtPointer)1 ) ;
  649.  
  650.         while( 1 )
  651.         {
  652.             XtAppNextEvent( appContext, &event ) ;
  653.             XtDispatchEvent( &event ) ;
  654.         }
  655.     }
  656.     else
  657.     {
  658.         vprintf( fmt, args ) ;
  659.         printf( "\n" ) ;
  660.         exit( 1 ) ;
  661.     }
  662.     va_end( args ) ;
  663. }
  664.  
  665.  
  666.  
  667. /*------------------------------------------------------------------------------
  668.  * Try to allocate memory, exiting if failure occurs.
  669.  *----------------------------------------------------------------------------*/
  670. void    *
  671. myMalloc(
  672.     size_t    size
  673.     )
  674. {
  675.     void    *ptr ;
  676.  
  677.     if( ( ptr = malloc( size ) ) == NULL )
  678.     {
  679.         fatalError( "Out of memory." ) ;
  680.     }
  681.  
  682.     return( ptr ) ;
  683. }
  684.  
  685.  
  686.  
  687. /*------------------------------------------------------------------------------
  688.  * Try to reallocate memory, exiting if failure occurs.
  689.  *----------------------------------------------------------------------------*/
  690. void    *
  691. myRealloc(
  692.     void    *ptr,
  693.     size_t    size
  694.     )
  695. {
  696.     void    *newPtr ;
  697.  
  698.     if( ( newPtr = realloc( ptr, size ) ) == NULL )
  699.     {
  700.         fatalError( "Out of memory." ) ;
  701.     }
  702.  
  703.     return( newPtr ) ;
  704. }
  705.  
  706.  
  707.  
  708. /*------------------------------------------------------------------------------
  709.  * Unmanage a widget.
  710.  *----------------------------------------------------------------------------*/
  711. void PopDownCB(
  712.     Widget callingWidget,
  713.     Widget doomedWidget,
  714.     caddr_t call_data
  715.     )
  716. {
  717.     XtUnmanageChild( doomedWidget ) ;
  718. }
  719.  
  720.  
  721.  
  722. /*------------------------------------------------------------------------------
  723.  * Extract a normal string from an XmString.
  724.  *----------------------------------------------------------------------------*/
  725. char *
  726. extractNormalString(
  727.     XmString    cs
  728.     )
  729. {
  730.     XmStringContext        context;
  731.     XmStringCharSet        charset;
  732.     XmStringDirection    direction;
  733.     Boolean            separator;
  734.     static char        *primitive_string;
  735.  
  736.     XmStringInitContext( &context, cs ) ;
  737.     XmStringGetNextSegment( context, &primitive_string, &charset,
  738.                 &direction, &separator ) ;
  739.     XmStringFreeContext( context ) ;
  740.     return( (char *)primitive_string ) ;
  741. }
  742.  
  743.  
  744.  
  745. /*------------------------------------------------------------------------------
  746.  * Normalize a 2D vector.
  747.  *----------------------------------------------------------------------------*/
  748. float
  749. normalizeVec2(
  750.     float    v[2]
  751.     )
  752. {
  753.     float    s ;
  754.  
  755.     s = v[0] * v[0] + v[1] * v[1] ;
  756.  
  757.     if( s > 0.0f )
  758.     {
  759.         s = sqrtf( s ) ;
  760.         v[0] /= s ;
  761.         v[1] /= s ;
  762.     }
  763.  
  764.     return( s ) ;
  765. }
  766.  
  767.  
  768.  
  769. /*------------------------------------------------------------------------------
  770.  * Show an information message.
  771.  *----------------------------------------------------------------------------*/
  772. static void
  773. showMessage(
  774.     char        *msg,
  775.     unsigned char    dialogType,
  776.     XtCallbackProc    callback,
  777.     XtPointer    userData
  778.     )
  779. {
  780.     int        n ;
  781.     Arg        args[10] ;
  782.     XmString    msgStr ;
  783.     XmString    titleStr ;
  784.     Widget        msgBox ;
  785.     Widget        button ;
  786.  
  787.     msgStr = XmStringCreateLtoR( msg, XmFONTLIST_DEFAULT_TAG ) ;
  788.  
  789.     n = 0 ;
  790.     XtSetArg( args[n], XmNmessageString, msgStr ) ; n++ ;
  791.     switch( dialogType )
  792.     {
  793.         case XmDIALOG_INFORMATION :
  794.         default :
  795.             titleStr = XmStringCreateLocalized( "Info" ) ;
  796.             XtSetArg( args[n], XmNdialogTitle, titleStr ) ; n++ ;
  797.             msgBox = XmCreateInformationDialog( topLevel,
  798.                     "msgBox", args, n ) ;
  799.             break ;
  800.  
  801.         case XmDIALOG_ERROR :
  802.             titleStr = XmStringCreateLocalized( "Error" ) ;
  803.             XtSetArg( args[n], XmNdialogTitle, titleStr ) ; n++ ;
  804.             XtSetArg( args[n], XmNdialogStyle,
  805.                 XmDIALOG_FULL_APPLICATION_MODAL ) ; n++ ;
  806.             msgBox = XmCreateErrorDialog( topLevel,
  807.                     "msgBox", args, n ) ;
  808.             break ;
  809.  
  810.         case XmDIALOG_WARNING :
  811.             titleStr = XmStringCreateLocalized( "Warning" ) ;
  812.             XtSetArg( args[n], XmNdialogTitle, titleStr ) ; n++ ;
  813.             XtSetArg( args[n], XmNdialogStyle,
  814.                 XmDIALOG_FULL_APPLICATION_MODAL ) ; n++ ;
  815.             msgBox = XmCreateWarningDialog( topLevel,
  816.                     "msgBox", args, n ) ;
  817.             break ;
  818.  
  819.         case XmDIALOG_MESSAGE :
  820.             titleStr = XmStringCreateLocalized( "Message" ) ;
  821.             XtSetArg( args[n], XmNdialogTitle, titleStr ) ; n++ ;
  822.             msgBox = XmCreateMessageDialog( topLevel,
  823.                     "msgBox", args, n ) ;
  824.             break ;
  825.     }
  826.  
  827.     if( callback != NULL )
  828.     {
  829.         XtAddCallback( msgBox, XmNokCallback, callback, userData ) ;
  830.     }
  831.  
  832.     button = XmMessageBoxGetChild( msgBox, XmDIALOG_CANCEL_BUTTON ) ;
  833.     XtUnmanageChild( button ) ;
  834.     button = XmMessageBoxGetChild( msgBox, XmDIALOG_HELP_BUTTON ) ;
  835.     XtUnmanageChild( button ) ;
  836.  
  837.     XmStringFree( msgStr ) ;
  838.     XmStringFree( titleStr ) ;
  839.  
  840.     XtManageChild( msgBox ) ;
  841. }
  842.  
  843.  
  844.  
  845. /*------------------------------------------------------------------------------
  846.  * Set up work procedures.
  847.  *----------------------------------------------------------------------------*/
  848. void
  849. setWorkProc(
  850.     long    wpMask,
  851.     int    mode
  852.     )
  853. {
  854.     /*
  855.      * If add a procedure...
  856.      */
  857.     if( mode )
  858.     {
  859.         workProcMask |= wpMask ;
  860.         /*
  861.          * If the master work procedure isn't running, start it.
  862.          */
  863.         if( workProcMask != 0 && lastWorkProc == 0 )
  864.         {
  865.             lastWorkProc = XtAppAddWorkProc( appContext,
  866.                             masterWorkProc, NULL ) ;
  867.         }
  868.     }
  869.     /*
  870.      * Remove a work procedure.
  871.      */
  872.     else
  873.     {
  874.         workProcMask &= ~wpMask ;
  875.         /*
  876.          * If no more work procedures, signal master work proc to end.
  877.          */
  878.         if( workProcMask == 0 && lastWorkProc != 0 )
  879.         {
  880.             lastWorkProc = 0 ;
  881.         }
  882.     }
  883. }
  884.  
  885.  
  886.  
  887. /*------------------------------------------------------------------------------
  888.  * Master work proc.
  889.  *----------------------------------------------------------------------------*/
  890. static Boolean
  891. masterWorkProc(
  892.     XtPointer    clientData
  893.     )
  894. {
  895.     static float    lastLoopTime = 0.0f ;
  896.  
  897. #if DEBUG
  898.     switch( freeTime )
  899.     {
  900.         case 1 :
  901.             currentTime = gameTime() ;
  902.             break ;
  903.  
  904.         case 0 :
  905.             currentTime += 0.1f ;
  906.             break ;
  907.  
  908.         default:
  909.             break ;
  910.     }
  911. #else
  912.     currentTime = gameTime() ;
  913. #endif /* DEBUG */
  914.  
  915.     if( workProcMask & VROOM_WP_RUN_SERVER )
  916.     {
  917.         /*
  918.          * Throttle server back to 15 frames per second to avoid
  919.          * flooding the net (and slower clients).
  920.          */
  921.         if( currentTime - lastLoopTime > 0.066f )
  922.         {
  923. #ifdef DEBUG
  924.             calculateFrameRate() ;
  925. #endif /* DEBUG */
  926.             serverRun() ;
  927.             lastLoopTime = currentTime ;
  928.         }
  929.     }
  930.  
  931.     if( workProcMask & VROOM_WP_RUN_CLIENT )
  932.     {
  933.         clientRun() ;
  934.     }
  935.  
  936.     if( workProcMask & VROOM_WP_SOLO )
  937.     {
  938.         /*
  939.          * Throttle server back to 30 frames per second to avoid
  940.          * some jumpiness on Extremes on small courses.
  941.          */
  942.         if( currentTime - lastLoopTime > 0.033f )
  943.         {
  944. #ifdef DEBUG
  945.             calculateFrameRate() ;
  946. #endif /* DEBUG */
  947.             soloLoop() ;
  948.             lastLoopTime = currentTime ;
  949.         }
  950.     }
  951.  
  952.     if( workProcMask & VROOM_WP_READ_SERVER )
  953.     {
  954.         serverRead() ;
  955.     }
  956.  
  957.     if( workProcMask & VROOM_WP_TIME_GRAPHICS )
  958.     {
  959.         timeGraphics() ;
  960.     }
  961.  
  962.     if( workProcMask & VROOM_WP_FIND_SERVER )
  963.     {
  964.         serverFind() ;
  965.     }
  966.  
  967. #ifdef DEBUG
  968.     checkGlError( basename ) ;
  969. #endif /* DEBUG */
  970.  
  971.     return( lastWorkProc == 0 ) ;
  972. }
  973.  
  974.  
  975.  
  976. /*------------------------------------------------------------------------------
  977.  * Callback to manage a widget.
  978.  *----------------------------------------------------------------------------*/
  979. void
  980. popUpCB(
  981.     Widget        w,
  982.     XtPointer    clientData,
  983.     XtPointer    callData
  984.     )
  985. {
  986.     XtManageChild( (Widget)clientData ) ;
  987. }
  988.  
  989.  
  990.  
  991. /*------------------------------------------------------------------------------
  992.  * Start the time trials.
  993.  *----------------------------------------------------------------------------*/
  994. void
  995. startTimeTrials(
  996.     int    skipTrial
  997.     )
  998. {
  999.     controlIntroWindow( 0 ) ;
  1000.  
  1001.     controlMainWindow( 1 ) ;
  1002.  
  1003.     defaultLod() ;
  1004.     currentTime = gameTime() ;
  1005.     if( playMode == VROOM_SOLO )
  1006.     {
  1007.         initSoloGame( skipTrial ) ;
  1008.     }
  1009.     else
  1010.     {
  1011.         initTeamGame() ;
  1012.     }
  1013.  
  1014.     noteTrackRecords() ;
  1015. }
  1016.  
  1017.  
  1018.  
  1019. /*------------------------------------------------------------------------------
  1020.  * Manage and unmanage the main window.
  1021.  *----------------------------------------------------------------------------*/
  1022. void
  1023. controlMainWindow(
  1024.     int    show
  1025.     )
  1026. {
  1027.     int            n ;
  1028.     Arg            arg[2] ;
  1029.     static int        init = 0 ;
  1030.     static Dimension    w ;
  1031.     static Dimension    h ;
  1032.  
  1033.     if( init == 0 )
  1034.     {
  1035.         init = 1 ;
  1036.         w = AppRes.mainWidth ;
  1037.         h = AppRes.mainHeight ;
  1038.         createMainWindow( topLevel, w, h ) ;
  1039.  
  1040.         if( show == 0 )
  1041.         {
  1042.             return ;
  1043.         }
  1044.         else
  1045.         {
  1046.             XtManageChild( mainWindow ) ;
  1047.         }
  1048.     }
  1049.     else
  1050.     {
  1051.         if( show )
  1052.         {
  1053.             XtManageChild( mainWindow ) ;
  1054.             n = 0 ;
  1055.             XtSetArg( arg[n], XmNwidth, w ) ; n++ ;
  1056.             XtSetArg( arg[n], XmNheight, h ) ; n++ ;
  1057.             XtSetValues( topLevel, arg, n ) ;
  1058.         }
  1059.         else
  1060.         {
  1061.             n = 0 ;
  1062.             XtSetArg( arg[n], XmNwidth, &w ) ; n++ ;
  1063.             XtSetArg( arg[n], XmNheight, &h ) ; n++ ;
  1064.             XtGetValues( mainWindow, arg, n ) ;
  1065.             XtUnmanageChild( mainWindow ) ;
  1066.         }
  1067.     }
  1068. }
  1069.  
  1070.  
  1071.  
  1072. /*------------------------------------------------------------------------------
  1073.  * Manage and unmanage the intro window.
  1074.  *----------------------------------------------------------------------------*/
  1075. void
  1076. controlIntroWindow(
  1077.     int    show
  1078.     )
  1079. {
  1080.     int            n ;
  1081.     Arg            arg[2] ;
  1082.     static int        init = 0 ;
  1083.     static Dimension    w = 800 ;
  1084.     static Dimension    h = 400 ;
  1085.  
  1086.     if( init == 0 )
  1087.     {
  1088.         init = 1 ;
  1089.  
  1090.         if( show == 1 )
  1091.         {
  1092.             XtManageChild( introWindow ) ;
  1093.         }
  1094.     }
  1095.     else
  1096.     {
  1097.         if( show )
  1098.         {
  1099.             setIntroCarShot() ;
  1100.             XtManageChild( introWindow ) ;
  1101.             n = 0 ;
  1102.             XtSetArg( arg[n], XmNwidth, w ) ; n++ ;
  1103.             XtSetArg( arg[n], XmNheight, h ) ; n++ ;
  1104.             XtSetValues( topLevel, arg, n ) ;
  1105.         }
  1106.         else
  1107.         {
  1108.             n = 0 ;
  1109.             XtSetArg( arg[n], XmNwidth, &w ) ; n++ ;
  1110.             XtSetArg( arg[n], XmNheight, &h ) ; n++ ;
  1111.             XtGetValues( introWindow, arg, n ) ;
  1112.             XtUnmanageChild( introWindow ) ;
  1113.         }
  1114.     }
  1115. }
  1116.  
  1117.  
  1118.  
  1119. /*------------------------------------------------------------------------------
  1120.  * Set the cursor to the busy symbol.
  1121.  *----------------------------------------------------------------------------*/
  1122. void
  1123. busyCursor(
  1124.     void
  1125.     )
  1126. {
  1127.     static Cursor    c = NULL ;
  1128.  
  1129.     if( c == NULL )
  1130.     {
  1131.         c = XCreateFontCursor( XtDisplay( topLevel ), XC_watch ) ;
  1132.     }
  1133.     XDefineCursor( XtDisplay( topLevel ), XtWindow( topLevel ), c ) ;
  1134. }
  1135.  
  1136.  
  1137.  
  1138. /*------------------------------------------------------------------------------
  1139.  * Set the cursor to the arrow symbol.
  1140.  *----------------------------------------------------------------------------*/
  1141. void
  1142. unbusyCursor(
  1143.     void
  1144.     )
  1145. {
  1146.     static Cursor    c = NULL ;
  1147.  
  1148.     if( c == NULL )
  1149.     {
  1150.         c = XCreateFontCursor( XtDisplay( topLevel ), XC_left_ptr ) ;
  1151.     }
  1152.     XDefineCursor( XtDisplay( topLevel ), XtWindow( topLevel ), c ) ;
  1153. }
  1154.  
  1155.  
  1156.  
  1157. /*------------------------------------------------------------------------------
  1158.  * Set message string.
  1159.  *----------------------------------------------------------------------------*/
  1160. void
  1161. setMessage(
  1162.     char    *fmt,
  1163.     ...
  1164.     )
  1165. {
  1166.     va_list        args ;
  1167.     char        msg[1024] ;
  1168.     Arg        arg[1] ;
  1169.     XmString    str ;
  1170.  
  1171.     va_start( args, fmt ) ;
  1172.     vsprintf( msg, fmt, args ) ;
  1173.  
  1174.     str = XmStringCreateLocalized( msg ) ;
  1175.     XtSetArg( arg[0], XmNlabelString, str ) ;
  1176.     XtSetValues( msgLabel, arg, 1 ) ;
  1177.     XmStringFree( str ) ;
  1178.  
  1179.     va_end( args ) ;
  1180. }
  1181.  
  1182.  
  1183.  
  1184. /*------------------------------------------------------------------------------
  1185.  * Convert time to min:sec.tenths format string.
  1186.  *----------------------------------------------------------------------------*/
  1187. char *
  1188. raceTimeString(
  1189.     float    t,
  1190.     int    *length
  1191.     )
  1192. {
  1193.     int        min ;
  1194.     int        sec ;
  1195.     int        tenths ;
  1196.     float        tt ;
  1197.     static char    str[9] ;
  1198.  
  1199.     tt = ABSFUNC( t ) ;
  1200.     min = (int)( tt / 60.0f ) ;
  1201.     tt -= 60.0f * min ;
  1202.     sec = (int)tt ;
  1203.     tenths = (int)( 10.0f * ( tt - sec ) ) ;
  1204.  
  1205.     min = min % 100 ;
  1206.     str[0] = '-' ;
  1207.     str[1] = '0' + min / 10 ;
  1208.     str[2] = '0' + min % 10 ;
  1209.     str[3] = ':' ;
  1210.     str[4] = '0' + sec / 10 ;
  1211.     str[5] = '0' + sec % 10 ;
  1212.     str[6] = '.' ;
  1213.     str[7] = '0' + tenths ;
  1214.     str[8] = '\0' ;
  1215.  
  1216.     if( t >= 0.0f )
  1217.     {
  1218.         *length = 8 ;
  1219.         return( str + 1 ) ;
  1220.     }
  1221.     else
  1222.     {
  1223.         *length = 9 ;
  1224.         return( str ) ;
  1225.     }
  1226. }
  1227.  
  1228.  
  1229.  
  1230. /*------------------------------------------------------------------------------
  1231.  * Convert time to min:sec.hundreths format string.
  1232.  *----------------------------------------------------------------------------*/
  1233. char *
  1234. longRaceTimeString(
  1235.     float    t,
  1236.     int    *length
  1237.     )
  1238. {
  1239.     int        min ;
  1240.     int        sec ;
  1241.     int        huns ;
  1242.     float        tt ;
  1243.     static char    str[10] ;
  1244.  
  1245.     tt = ABSFUNC( t ) ;
  1246.     min = (int)( tt / 60.0f ) ;
  1247.     tt -= 60.0f * min ;
  1248.     sec = (int)tt ;
  1249.     huns = (int)( 100.0f * ( tt - sec ) ) ;
  1250.  
  1251.     min = min % 100 ;
  1252.     str[0] = '-' ;
  1253.     str[1] = '0' + min / 10 ;
  1254.     str[2] = '0' + min % 10 ;
  1255.     str[3] = ':' ;
  1256.     str[4] = '0' + sec / 10 ;
  1257.     str[5] = '0' + sec % 10 ;
  1258.     str[6] = '.' ;
  1259.     str[7] = '0' + huns / 10 ;
  1260.     str[8] = '0' + huns % 10 ;
  1261.     str[9] = '\0' ;
  1262.  
  1263.     if( t >= 0.0f )
  1264.     {
  1265.         *length = 8 ;
  1266.         return( str + 1 ) ;
  1267.     }
  1268.     else
  1269.     {
  1270.         *length = 9 ;
  1271.         return( str ) ;
  1272.     }
  1273. }
  1274.  
  1275.  
  1276.  
  1277. /*------------------------------------------------------------------------------
  1278.  * Pick a random number and return whether it is below a threshhold number.
  1279.  *----------------------------------------------------------------------------*/
  1280. Boolean
  1281. randomChoice(
  1282.     float    threshhold
  1283.     )
  1284. {
  1285.     float    x ;
  1286.  
  1287.     x = (float)( rand() % 0x0ff ) / (float)( 0x0ff ) ;
  1288.  
  1289.     return( x < threshhold ) ;
  1290. }
  1291.  
  1292.  
  1293.  
  1294. /*------------------------------------------------------------------------------
  1295.  * Determine my player's name.
  1296.  *----------------------------------------------------------------------------*/
  1297. static void
  1298. determineMyName(
  1299.     void
  1300.     )
  1301. {
  1302.     char    *s ;
  1303.     char    tmp[L_cuserid] ;
  1304.  
  1305.     if( ( s = getenv( "VROOM_NAME" ) ) != NULL )
  1306.     {
  1307.         myName = strdup( s ) ;
  1308.     }
  1309.     else if( AppRes.name != NULL && strlen( AppRes.name ) > 0 )
  1310.     {
  1311.         myName = AppRes.name ;
  1312.     }
  1313.     else
  1314.     {
  1315.         cuserid( tmp ) ;
  1316.  
  1317.         myName = strdup( tmp ) ;
  1318.     }
  1319. }
  1320.  
  1321.  
  1322.  
  1323. /*------------------------------------------------------------------------------
  1324.  * Determine the default data directory.
  1325.  *----------------------------------------------------------------------------*/
  1326. static void
  1327. getDefaultDataDir(
  1328.     void
  1329.     )
  1330. {
  1331.     char    *d ;
  1332.     int    recDirMode ;
  1333.  
  1334.     if( ( d = getenv( "VROOM_DIR" ) ) != NULL )
  1335.     {
  1336.         defaultDataDir = d ;
  1337.     }
  1338.     else if( AppRes.defaultDataDir != NULL &&
  1339.         strlen( AppRes.defaultDataDir ) > 0 )
  1340.     {
  1341.         defaultDataDir = AppRes.defaultDataDir ;
  1342.     }
  1343.     if( defaultDataDir == NULL || strlen( defaultDataDir ) == 0 )
  1344.     {
  1345.         defaultDataDir = strdup( VROOM_DEFAULT_DIR ) ;
  1346.     }
  1347.  
  1348.     if( ( d = getenv( "VROOM_REC_DIR" ) ) != NULL )
  1349.     {
  1350.         recDirMode = 1 ;
  1351.         defaultRecDir = d ;
  1352.     }
  1353.     else if( AppRes.defaultRecDir != NULL &&
  1354.         strlen( AppRes.defaultRecDir ) > 0 )
  1355.     {
  1356.         recDirMode = 2 ;
  1357.         defaultRecDir = AppRes.defaultRecDir ;
  1358.     }
  1359.     if( defaultRecDir == NULL || strlen( defaultRecDir ) == 0 )
  1360.     {
  1361.         recDirMode = 0 ;
  1362.         defaultRecDir = strdup( VROOM_DEFAULT_REC_DIR ) ;
  1363.     }
  1364.  
  1365.     /*
  1366.      * Make sure directories exist and are readable.
  1367.      */
  1368.     if( access( defaultDataDir, F_OK ) < 0 )
  1369.     {
  1370.         fatalError( "Can not access data directory:\n\n%s\n\n"
  1371.             "Check the setting of the VROOM_DIR environment\n"
  1372.             "variable.", defaultDataDir ) ;
  1373.     }
  1374.  
  1375.     if( access( defaultRecDir, F_OK | W_OK ) < 0 )
  1376.     {
  1377.         switch( recDirMode )
  1378.         {
  1379.             case 0 :
  1380.             minorError( NULL, NULL,
  1381.             "Can not write to the default records directory:\n"
  1382.             "\n\t%s\n\n"
  1383.             "You will be unable to save any track records.  You\n"
  1384.             "can set the VROOM_REC_DIR environment variable or\n"
  1385.             "Vroom*defaultRecDir resource to override the default\n"
  1386.             "directory setting.", defaultRecDir ) ;
  1387.             break ;
  1388.  
  1389.             case 1 :
  1390.             minorError( NULL, NULL,
  1391.             "Can not write to the records directory:\n"
  1392.             "\n\t%s\n\n"
  1393.             "specified by the environment variable VROOM_REC_DIR.\n"
  1394.             "You will be unable to save any track records.",
  1395.             defaultRecDir ) ;
  1396.             break ;
  1397.  
  1398.             case 2 :
  1399.             minorError( NULL, NULL,
  1400.             "Can not write to the records directory:\n"
  1401.             "\n\t%s\n\n"
  1402.             "specified by the resource value Vroom*defaultRecDir.\n"
  1403.             "You will be unable to save any track records.",
  1404.             defaultRecDir ) ;
  1405.             break ;
  1406.         }
  1407.     }
  1408. }
  1409.  
  1410.  
  1411.  
  1412. /*------------------------------------------------------------------------------
  1413.  * Help program callback function definition.
  1414.  *----------------------------------------------------------------------------*/
  1415. void
  1416. helpCB(
  1417.     Widget        w,
  1418.     XtPointer    clientData,
  1419.     XtPointer    callData
  1420.     )
  1421. {
  1422.     Widget        help ;
  1423.     char        **helpFileName = (char **)clientData ;
  1424.     char        *helpMessage = NULL ;
  1425.  
  1426.     if( ( helpMessage = getHelpMessage( helpFileName[0] ) ) == NULL )
  1427.     {
  1428.         return ;
  1429.     }
  1430.  
  1431.     help = createHelpWidget( w, helpMessage, helpCB, &(helpFileName[1]) ) ;
  1432.  
  1433.     free( helpMessage ) ;
  1434.  
  1435.     XtManageChild( help ) ;
  1436. }
  1437.  
  1438.  
  1439.  
  1440. /*------------------------------------------------------------------------------
  1441.  * Load in a help file.
  1442.  *----------------------------------------------------------------------------*/
  1443. static char *
  1444. getHelpMessage(
  1445.     char    *file
  1446.     )
  1447. {
  1448.     FILE        *f ;
  1449.     char        *helpMessage = NULL ;
  1450.     struct stat    st ;
  1451.     char        name[FILENAME_MAX] ;
  1452.  
  1453.     sprintf( name, "%s/%s", defaultDataDir, file ) ;
  1454.  
  1455.     if( ( f = fopen( name, "r" ) ) == NULL )
  1456.     {
  1457.         minorError( NULL, NULL, "Could not locate help file:  `%s'.\n"
  1458.             "Set the environment variable, VROOM_DIR, to "
  1459.             "indicate the correct directory.", name ) ;
  1460.     }
  1461.     else if( fstat( fileno(f), &st ) == -1 )
  1462.     {
  1463.         minorError( NULL, NULL, "Could not determine the size of the"
  1464.             " help file:\n`%s'.", name ) ;
  1465.     }
  1466.     else if( ( helpMessage = (char *)malloc( st.st_size + 1 ) ) == NULL )
  1467.     {
  1468.         minorError( NULL, NULL, "Can not allocate enough space to read"
  1469.                 " in the help file." ) ;
  1470.     }
  1471.     else if( fread( helpMessage, sizeof( char ), st.st_size, f )
  1472.         != st.st_size )
  1473.     {
  1474.         minorError( NULL, NULL, "Error reading the help file `%s'.",
  1475.             name ) ;
  1476.         free( helpMessage ) ;
  1477.         helpMessage = NULL ;
  1478.     }
  1479.     else
  1480.     {
  1481.         if( helpMessage[st.st_size-1] == '\n' )
  1482.         {
  1483.             helpMessage[st.st_size-1] = '\0' ;
  1484.         }
  1485.         else
  1486.         {
  1487.             helpMessage[st.st_size] = '\0' ;
  1488.         }
  1489.     }
  1490.  
  1491.     return( helpMessage ) ;
  1492. }
  1493.  
  1494.  
  1495.  
  1496. /*------------------------------------------------------------------------------
  1497.  * Create the help pop-up window.
  1498.  *----------------------------------------------------------------------------*/
  1499. static Widget
  1500. createHelpWidget(
  1501.     Widget        parent,
  1502.     char        *helpMessage,
  1503.     XtCallbackProc    nextHelp,
  1504.     char        **helpFileName
  1505.     )
  1506. {
  1507.     int        n ;
  1508.     Widget        helpButton ;
  1509.     XmString    helpStr ;
  1510.     XmString    titleStr ;
  1511.     int        nLines ;
  1512.     Widget        help ;
  1513.     Arg        args[10] ;
  1514.  
  1515.     nLines = numberOfLines( helpMessage ) ;
  1516.  
  1517.     if( nLines > MAX_VISIBLE_HELP_LINES )
  1518.     {
  1519.         help = createScrolledTextDialog( parent, helpMessage, nextHelp,
  1520.                         helpFileName ) ;
  1521.     }
  1522.     else
  1523.     {
  1524.         n = 0 ;
  1525.         helpStr = XmStringCreateLtoR( helpMessage,
  1526.                         XmFONTLIST_DEFAULT_TAG ) ;
  1527.         XtSetArg( args[n], XmNmessageString,  helpStr ) ; n++ ;
  1528.         titleStr = XmStringCreateLocalized( "Help" ) ;
  1529.         XtSetArg( args[n], XmNdialogTitle, titleStr ) ; n++ ;
  1530.         help = XmCreateInformationDialog( parent, "helpPage", args, n );
  1531.         XmStringFree( helpStr ) ;
  1532.         XmStringFree( titleStr ) ;
  1533.         if( helpFileName[0] != NULL )
  1534.         {
  1535.             XtAddCallback( help, XmNhelpCallback, helpCB,
  1536.                     helpFileName ) ;
  1537.         }
  1538.         else
  1539.         {
  1540.             helpButton = XmMessageBoxGetChild( help,
  1541.                         XmDIALOG_HELP_BUTTON );
  1542.             XtUnmanageChild( helpButton ) ;
  1543.         }
  1544.  
  1545.         XtUnmanageChild( XmMessageBoxGetChild( help,
  1546.                         XmDIALOG_CANCEL_BUTTON ) );
  1547.     }
  1548.  
  1549.     return( help ) ;
  1550. }
  1551.  
  1552.  
  1553.  
  1554. /*------------------------------------------------------------------------------
  1555.  * Determine the number of lines in a string.
  1556.  *----------------------------------------------------------------------------*/
  1557. static int
  1558. numberOfLines(
  1559.     const char    *text
  1560.     )
  1561. {
  1562.     int nLines = 0 ;
  1563.  
  1564.     while( *text != '\0' )
  1565.     {
  1566.         if( *(text++) == '\n' ) nLines++ ;
  1567.     }
  1568.  
  1569.     return( nLines ) ;
  1570. }
  1571.  
  1572.  
  1573.  
  1574. /*------------------------------------------------------------------------------
  1575.  * Make a dialog window containing scrolled text.
  1576.  *----------------------------------------------------------------------------*/
  1577. static Widget
  1578. createScrolledTextDialog(
  1579.     Widget        parent,
  1580.     char        *helpMessage,
  1581.     XtCallbackProc    nextHelp,
  1582.     char        **helpFileName
  1583.     )
  1584. {
  1585.     Widget        help ;
  1586.     Widget        helpText ;
  1587.     Widget        separator ;
  1588.     Widget        okButton ;
  1589.     Widget        helpButton ;
  1590.     Widget        rowOfButtons ;
  1591.     XmString    titleStr ;
  1592.     int        n ;
  1593.     Arg        args[15] ;
  1594.  
  1595.     n = 0 ;
  1596.     XtSetArg( args[n], XmNautoUnmanage, False ) ; n++ ;
  1597.     titleStr = XmStringCreateLocalized( "Help" ) ;
  1598.     XtSetArg( args[n], XmNdialogTitle, titleStr ) ; n++ ;
  1599.     help = XmCreateFormDialog( parent, "helpPage", args, n ) ;
  1600.     XmStringFree( titleStr ) ;
  1601.  
  1602.     n = 0 ;
  1603.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_FORM ) ; n++ ;
  1604.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  1605.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  1606.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_NONE ) ; n++ ;
  1607.     XtSetArg( args[n], XmNwidth, 500 ) ; n++ ;
  1608.     XtSetArg( args[n], XmNeditMode, XmMULTI_LINE_EDIT ) ; n++ ;
  1609.     XtSetArg( args[n], XmNwordWrap, True ) ; n++ ;
  1610.     XtSetArg( args[n], XmNrows, MAX_VISIBLE_HELP_LINES ) ; n++ ;
  1611.     helpText = XmCreateScrolledText( help, "helpText", args, n ) ;
  1612.     XtManageChild( helpText ) ;
  1613.     XmTextSetString( helpText, helpMessage ) ;
  1614.     n = 0 ;
  1615.     XtSetArg( args[n], XmNeditable, False ) ; n++ ;
  1616.     XtSetValues( helpText, args, n ) ;
  1617.  
  1618.     n = 0 ;
  1619.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_WIDGET ) ; n++ ;
  1620.     XtSetArg( args[n], XmNtopWidget, helpText ) ; n++ ;
  1621.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  1622.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  1623.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_NONE ) ; n++ ;
  1624.     separator = XtCreateManagedWidget( "separator", xmSeparatorWidgetClass,
  1625.                     help, args, n );
  1626.  
  1627.     n = 0 ;
  1628.     XtSetArg( args[n], XmNspacing, 10 ) ; n++ ;
  1629.     XtSetArg( args[n], XmNborderWidth, 0 ) ; n++ ;
  1630.     XtSetArg( args[n], XmNtopAttachment, XmATTACH_WIDGET ) ; n++ ;
  1631.     XtSetArg( args[n], XmNtopWidget, separator ) ; n++ ;
  1632.     XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM ) ; n++ ;
  1633.     XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM ) ; n++ ;
  1634.     XtSetArg( args[n], XmNbottomAttachment, XmATTACH_FORM ) ; n++ ;
  1635.     rowOfButtons = XtCreateManagedWidget( "helpButtons",
  1636.                 xsRowWidgetClass, help, args, n ) ;
  1637.  
  1638.     n = 0 ;
  1639.     XtSetArg( args[n], XmNmarginHeight, 5 ) ; n++ ;
  1640.     XtSetArg( args[n], XmNmarginWidth, 5 ) ; n++ ;
  1641.     okButton = XtCreateManagedWidget( "Ok", xmPushButtonWidgetClass,
  1642.                     rowOfButtons, args, n ) ;
  1643.     XtAddCallback( okButton, XmNactivateCallback, destroyWidgetCB, help ) ;
  1644.  
  1645.     if( helpFileName[0] != NULL )
  1646.     {
  1647.         helpButton = XtCreateManagedWidget( "Help",
  1648.                     xmPushButtonWidgetClass, rowOfButtons,
  1649.                     args, n ) ;
  1650.         XtAddCallback( helpButton, XmNactivateCallback, nextHelp,
  1651.                 helpFileName ) ;
  1652.     }
  1653.     return( help ) ;
  1654. }
  1655.  
  1656.  
  1657.  
  1658. /*------------------------------------------------------------------------------
  1659.  * Destroy a widget.
  1660.  *----------------------------------------------------------------------------*/
  1661. static void
  1662. destroyWidgetCB(
  1663.     Widget        w,
  1664.     XtPointer    clientData,
  1665.     XtPointer    callData
  1666.     )
  1667. {
  1668.     XtDestroyWidget( (Widget)clientData ) ;
  1669. }
  1670.  
  1671.  
  1672.  
  1673. /*------------------------------------------------------------------------------
  1674.  * Show about message.
  1675.  *----------------------------------------------------------------------------*/
  1676. void
  1677. aboutCB(
  1678.     Widget        w,
  1679.     XtPointer    clientData,
  1680.     XtPointer    callData
  1681.     )
  1682. {
  1683.     postInfo( NULL, NULL,    "VROOM - slot cars of the future\n\n"
  1684.                 "Chris Fouts - May 1994 - Version 1.1" ) ;
  1685. }
  1686.  
  1687.  
  1688.  
  1689. /*------------------------------------------------------------------------------
  1690.  * Pop-up help file on racing.
  1691.  *----------------------------------------------------------------------------*/
  1692. void
  1693. showRaceHelpCB(
  1694.     Widget        w,
  1695.     XtPointer    clientData,
  1696.     XtPointer    callData
  1697.     )
  1698. {
  1699.     static char    *localHelpFiles[] = { "localrace.help", NULL } ;
  1700.     static char    *netHelpFiles[] = { "netrace.help", NULL } ;
  1701.  
  1702.     if( playMode == VROOM_SOLO )
  1703.     {
  1704.         helpCB( mainWindow, (XtPointer)localHelpFiles, NULL ) ;
  1705.     }
  1706.     else
  1707.     {
  1708.         helpCB( mainWindow, (XtPointer)netHelpFiles, NULL ) ;
  1709.     }
  1710. }
  1711.  
  1712.  
  1713.  
  1714. /*------------------------------------------------------------------------------
  1715.  * Return the default time-to-live setting for server broadcasts.
  1716.  *----------------------------------------------------------------------------*/
  1717. int
  1718. getTtl(
  1719.     void
  1720.     )
  1721. {
  1722.     if( AppRes.ttl < 1 )
  1723.     {
  1724.         AppRes.ttl = 1 ;
  1725.     }
  1726.     else if( AppRes.ttl > 32 )
  1727.     {
  1728.         AppRes.ttl = 32 ;
  1729.     }
  1730.  
  1731.     return( AppRes.ttl ) ;
  1732. }
  1733.  
  1734.  
  1735.  
  1736. /*------------------------------------------------------------------------------
  1737.  * Initialize the sound routines.
  1738.  *----------------------------------------------------------------------------*/
  1739. static void
  1740. initSound(
  1741.     void
  1742.     )
  1743. {
  1744.     int    err ;
  1745.  
  1746.     err = sfxInit( defaultDataDir, 3 ) ;
  1747.  
  1748.     if( err == SFX_ERR_NO_PORTS_AVAIL )
  1749.     {
  1750.         postInfo( NULL, NULL, "No audio ports are available." );
  1751.     }
  1752.     else if( err == SFX_ERR_NO_SPROC )
  1753.     {
  1754.         postInfo( NULL, NULL, "Unable to execute sound "
  1755.                 "process." );
  1756.     }
  1757.     else if( err == SFX_ERR_NO_MEM )
  1758.     {
  1759.         postInfo( NULL, NULL, "No memory available for sound"
  1760.                 "data." );
  1761.     }
  1762.     else if( err > 0 )
  1763.     {
  1764.         introSfx    = sfxLoad( "intro.aifc" ) ;
  1765.         toneSfx        = sfxLoad( "tone1.aifc" ) ;
  1766.         startSfx    = sfxLoad( "start.aifc" ) ;
  1767.         crashSfx    = sfxLoad( "crash.aifc" ) ;
  1768.         alertSfx    = sfxLoad( "alert.aifc" ) ;
  1769.         collideSfx    = sfxLoad( "collide.aifc" ) ;
  1770.         cheerSfx    = sfxLoad( "cheers.aifc" ) ;
  1771.         changeLaneSfx    = sfxLoad( "changelane.aifc" ) ;
  1772.         lastlapSfx    = sfxLoad( "lastlap.aifc" ) ;
  1773.         if( err > 1 )
  1774.         {
  1775.             squealSfx = sfxLoad( "squeal.aifc" ) ;
  1776.             sfxLoop( squealSfx ) ;
  1777.             if( err > 2 )
  1778.             {
  1779.                 motorSfx = sfxLoad( "motor.aifc" ) ;
  1780.                 sfxLoop( motorSfx ) ;
  1781.                 sfxPitchBend( motorSfx, 0.0f, 1.0f, 1.0f,
  1782.                         2.0f, 1.1f, 20 ) ;
  1783.             }
  1784.         }
  1785.         sfxPlay( introSfx ) ;
  1786.     }
  1787. }
  1788.  
  1789.  
  1790.  
  1791. /*------------------------------------------------------------------------------
  1792.  * Set the admininistration form (unmanage previous form).
  1793.  *----------------------------------------------------------------------------*/
  1794. void
  1795. setAdminForm(
  1796.     Widget    newForm
  1797.     )
  1798. {
  1799.     static Widget    oldForm = NULL ;
  1800.  
  1801.     if( oldForm != NULL )
  1802.     {
  1803.         XtUnmanageChild( oldForm ) ;
  1804.     }
  1805.     XtManageChild( newForm ) ;
  1806.  
  1807.     oldForm = newForm ;
  1808. }
  1809.  
  1810.  
  1811.  
  1812. /*------------------------------------------------------------------------------
  1813.  * Calculate the current frame rate (over 1 second intervals).
  1814.  *----------------------------------------------------------------------------*/
  1815. static void
  1816. calculateFrameRate(
  1817.     void
  1818.     )
  1819. {
  1820.     static float    lastTime = 0.0f ;
  1821.     static int    nFrames = 0 ;
  1822.     static int    dTime = 0.0f ;
  1823.  
  1824.     nFrames++ ;
  1825.     if( currentTime - dTime >= 1.0f )
  1826.     {
  1827.         frameRate = nFrames / ( currentTime - dTime ) ;
  1828.         dTime = currentTime ;
  1829.         nFrames = 0 ;
  1830.     }
  1831.  
  1832.     lastTime = currentTime ;
  1833. }
  1834.